package cn.com.dhcc.turbo.service.monitor.compute;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import cn.com.dhcc.app.core.CM;
import cn.com.dhcc.app.core.exception.DaoException;
import cn.com.dhcc.app.core.exception.NiceException;
import cn.com.dhcc.app.core.exception.ServiceException;
import cn.com.dhcc.app.core.service.Log;
import cn.com.dhcc.app.core.service.Log.LOGTYPE;
import cn.com.dhcc.app.core.tag.CommonStaticCode.YESNO;
import cn.com.dhcc.app.core.util.CollectionUtil;
import cn.com.dhcc.app.core.util.FreemarkerUtil;
import cn.com.dhcc.app.core.util.StrUtil;
import cn.com.dhcc.turbo.entity.monitor.Quota;
import cn.com.dhcc.turbo.entity.monitor.QuotaComputeRule;
import cn.com.dhcc.turbo.entity.monitor.QuotaConf;
import cn.com.dhcc.turbo.entity.monitor.QuotaValueOnTime;
import cn.com.dhcc.turbo.entity.monitor.QuotaValueOnTime.QuotaHadlerStatus;
import cn.com.dhcc.turbo.entity.registry.AdapterInfo;
import cn.com.dhcc.turbo.entity.registry.NodeInfo;
import cn.com.dhcc.turbo.service.monitor.MonitorQuotaStatic.ALERT_PIPELINE;
import cn.com.dhcc.turbo.service.monitor.MonitorQuotaStatic.PLACEHOLDER;
import cn.com.dhcc.turbo.service.monitor.MonitorQuotaStatic.QUOTA_OWNER;
import cn.com.dhcc.turbo.service.monitor.MonitorService;
import cn.com.dhcc.turbo.service.registry.AdapterInfoService;
import cn.com.dhcc.turbo.service.registry.NodeInfoService;


/**
 * 通用的告警指标处理
 * @author qiao
 * @2014-6-4 @下午2:31:16
 */
@Service
public class CommonCompute implements MonitorComputeInterface{

	@SuppressWarnings("deprecation")
	Logger logger = Log.getExistLogger(LOGTYPE.MONITOR);
	@Autowired
	MonitorService monitorService;
	@Autowired
	NodeInfoService infoService;
	
	@Autowired
	AdapterInfoService adapterInfoService;
	
	@Override
	public void merge(List<QuotaValueOnTime> onTimes,Quota quota,QuotaComputeRule computeRule,QuotaConf conf) throws ServiceException {
		//先移动，一般最后就留下最新的一条
		moveToHistory(onTimes, quota, computeRule, conf);
	}

	@Override
	public void computeAlert(List<QuotaValueOnTime> onTimes,Quota quota,QuotaComputeRule computeRule,QuotaConf conf) throws ServiceException, NiceException {
		if(CollectionUtil.hasElement(onTimes)){
			//如果需要告警的指标才去计算,并且只计算最新的一条
			if(YESNO.YES.getStatus().equalsIgnoreCase(quota.getAlterAble())){
				for (Iterator<QuotaValueOnTime> iterator = onTimes.iterator(); iterator.hasNext();) {
					QuotaValueOnTime quotaValueOnTime = iterator.next();
					if(quotaValueOnTime.getNeedAlert()==null){//已经计算过了就不计算了
						computeAlert(quotaValueOnTime, quota, computeRule, conf);
					}
				}
			}else{
				return;
			}
		}
	}

	//远程节点为连接状态异常时的部分指标默认显示值，此值不从计算，直接告警处理
	public static String DEFALUT_NOT_COMPUTE_VALUE = "N/A";
	//计算
	private void computeAlert(QuotaValueOnTime quotaValueOnTime, Quota quota,
			QuotaComputeRule computeRule, QuotaConf conf) throws NiceException, ServiceException {
		//规则：
		//1 先看有没有用户自定义的阈值配置，如果没有，采用系统建议的值就行计算;
		String rulecontent = computeRule.getRuleContent();//计算规则
		String confValue1 = null;//阈值1
		String confValue2 = null;//阈值2
		if(conf==null){
			confValue1 = quota.getValueSug1();
			confValue2 = quota.getValueSug2();
		}else{
			confValue1 = conf.getValue1();
			confValue2 = conf.getValue2();
		}
		boolean alter = false;
		//默认值为DEFALUT_NOT_COMPUTE_VALUE的全部告警
		if(DEFALUT_NOT_COMPUTE_VALUE.equalsIgnoreCase(quotaValueOnTime.getCurrentValue1())
				||DEFALUT_NOT_COMPUTE_VALUE.equalsIgnoreCase(quotaValueOnTime.getCurrentValue2())){
			logger.info("指标["+quota.getName()+"]的值为["+DEFALUT_NOT_COMPUTE_VALUE+"]，默认处理为:"+(alter?"操作阈值，需要告警":"不需要告警"));
			alter = true;
		}else{
			String express;
			try {
				express = createExpress(rulecontent, confValue1, confValue2, quotaValueOnTime);
				logger.info("指标["+quota.getName()+"]的告警计算公式:"+express+"?");
			} catch (NiceException e) {
				logger.error("生成告警计算公式失败",e);
				throw e;
			}
			alter = monitorService.expressCompute(express);
			logger.info("指标["+quota.getName()+"]的阈值计算结果:"+(alter?"操作阈值，需要告警":"不需要告警"));
		}
		quotaValueOnTime.setNeedAlert(alter?YESNO.YES.getStatus():YESNO.NO.getStatus());
		//生成告警信息
		if(alter){
			if(!StrUtil.isNotBank(quotaValueOnTime.getAlertMsg())){
				String alertMsg = createAlertMsg(quota,quotaValueOnTime, confValue1, confValue2);
				logger.info("生成指标["+quota.getName()+"]告警信息:"+alertMsg);
				quotaValueOnTime.setAlertMsg(alertMsg);
			}
		}
		try {
			CM.getDao().updateModuleById("设置告警", quotaValueOnTime,new String[]{});
		} catch (DaoException e) {
			throw new ServiceException("设置告警出错");
		}
	}
	/**
	 * onTimesByQuotaCode 按时间倒序排列的记录
	 */
	@Override
	public void moveToHistory(List<QuotaValueOnTime> onTimesByQuotaCode,Quota quota,QuotaComputeRule computeRule,QuotaConf conf) throws ServiceException {
		List<QuotaValueOnTime> onTimesToMove = new ArrayList<QuotaValueOnTime>();
		Map<String, List<QuotaValueOnTime>> quotaValueNotRemoveGroupByOwnerId = new HashMap<String, List<QuotaValueOnTime>>();
		//开始按告警归属ownerId分组
		for (Iterator<QuotaValueOnTime> iterator = onTimesByQuotaCode.iterator(); iterator
				.hasNext();) {
			QuotaValueOnTime quotaValueOnTime = iterator.next();
			String ownerId = quotaValueOnTime.getOwnerId();
			if(quotaValueNotRemoveGroupByOwnerId.get(ownerId)==null){
				quotaValueNotRemoveGroupByOwnerId.put(ownerId, new ArrayList<QuotaValueOnTime>());
			}
			
			if(quotaValueNotRemoveGroupByOwnerId.get(ownerId).size()==1){
				onTimesToMove.add(quotaValueOnTime);////归属于同一个的ownerId的记录只保留最新的一条（保留最新的）,如果已经有一条了，其他的都加入删除集合
				iterator.remove();
				continue;
			}
			quotaValueNotRemoveGroupByOwnerId.get(ownerId).add(quotaValueOnTime);
		}
		Date handlerTime = new Date();
		for (Iterator<QuotaValueOnTime> iterator = onTimesToMove.iterator(); iterator.hasNext();) {
			QuotaValueOnTime quotaValueOnTime = iterator.next();
			if(!StringUtils.hasText(quotaValueOnTime.getHasAlertMethod())){
				quotaValueOnTime.setHandlerTime(handlerTime);
				quotaValueOnTime.setHasAlertMethod(ALERT_PIPELINE.AUTO_CLOSE.getCode());
				quotaValueOnTime.setStatus(QuotaHadlerStatus.HAS_HANDLER.getCode());
			}
			monitorService.moveOnTimeMonitorToHistory(quotaValueOnTime);
		}
	}
	/**
	 * 将小于某个时间以前的记录移到历史,一般之针对不需要告警的指标
	 * @param onTimes
	 * @throws ServiceException 
	 */
	public void moveBeforeTimeRowsToHistory(List<QuotaValueOnTime> onTimes,Date timeLine) throws ServiceException{
		List<QuotaValueOnTime> onTimesToMove = onTimes.subList(1, onTimes.size());
		for (Iterator<QuotaValueOnTime> iterator = onTimesToMove.iterator(); iterator
				.hasNext();) {
			QuotaValueOnTime quotaValueOnTime = iterator.next();
			long time = quotaValueOnTime.getMtime().getTime();
			if(time<timeLine.getTime()){
			  monitorService.moveOnTimeMonitorToHistory(quotaValueOnTime);
			  iterator.remove();
			}
		}
	}
	/*
	 * 根据计算规则和配置的阈值和实际值得出计算表达式
	 */
	public String createExpress(String rulecontent,String confValue1,String confValue2,QuotaValueOnTime valueOnTime) throws NiceException {
	    String result = null;
	    Map<String, Object> rootMap = new HashMap<String, Object>();
	    rootMap.put(PLACEHOLDER.CURRENT_VALUE_1.getKey(), valueOnTime.getCurrentValue1());
	    rootMap.put(PLACEHOLDER.CURRENT_VALUE_2.getKey(), valueOnTime.getCurrentValue2());
	    rootMap.put(PLACEHOLDER.CONF_VALUE_1.getKey(), confValue1);
	    rootMap.put(PLACEHOLDER.CONF_VALUE_2.getKey(), confValue2);
	    StringWriter out = new StringWriter();
	    try {
			FreemarkerUtil.flushStringTemplateData(rulecontent, out, rootMap);
		} catch (Exception e) {
			logger.error("解析指标计算规则出错",e);
			throw new NiceException("解析指标计算规则出错",e);
		} 
	    result = out.toString();
		return result;
	}
	//根据模板，生成每个指标的告警信息
	public String createAlertMsg(Quota quota, QuotaValueOnTime valueOnTime,
			String confValue1,String confValue2) throws NiceException, ServiceException {
		String alertTemplate = quota.getAlterTemplatSug();//使用默认模板//TODO 暂时不使用用户自定义模板
		
		Map<String, Object> rootMap = new HashMap<String, Object>();
		String result = null;
		String ownerId = valueOnTime.getOwnerId();
		String ownerType = quota.getOwner();
		//1，如果是ownerId是两个值，则代表区间 ，需要查出区间的节点名称或者系统2 如果是系统，这查出系统所属的节点和系统名
		if(StrUtil.isNotBank(ownerId)){
			String[] ownerIds = ownerId.split("\\|");
			if(ownerIds.length==1){
				if(QUOTA_OWNER.NODE.getCode().equalsIgnoreCase(ownerType)){
					NodeInfo nodeInfo = infoService.get(ownerId);
					rootMap.put(PLACEHOLDER.NODE_NAME.getKey(), nodeInfo==null?"":nodeInfo.getNodeName());
				}
				if(QUOTA_OWNER.ADAPTER.getCode().equalsIgnoreCase(ownerType)){
					AdapterInfo adapterInfo = adapterInfoService.get(ownerId);
				    rootMap.put(PLACEHOLDER.ADAPTER_NAME.getKey(), adapterInfo==null?"":adapterInfo.getAdapterName());
				}
			}else{
				if(QUOTA_OWNER.NODE.getCode().equalsIgnoreCase(ownerType)){
					NodeInfo nodeInfo_from = infoService.get(ownerIds[0]);
					NodeInfo nodeInfo_to = infoService.get(ownerIds[1]);
					rootMap.put(PLACEHOLDER.NODE_NAME_FROM.getKey(), nodeInfo_from==null?"":nodeInfo_from.getNodeName());
				    rootMap.put(PLACEHOLDER.NODE_NAME_TO.getKey(),  nodeInfo_to==null?"":nodeInfo_to.getNodeName());
				}
				if(QUOTA_OWNER.ADAPTER.getCode().equalsIgnoreCase(ownerType)){
					AdapterInfo adapter_from = adapterInfoService.get(ownerIds[0]);
					AdapterInfo adapter_to = adapterInfoService.get(ownerIds[1]);
				    rootMap.put(PLACEHOLDER.ADAPTER_NAME_FROM.getKey(),  adapter_from==null?"":adapter_from.getAdapterName());
				    rootMap.put(PLACEHOLDER.ADAPTER_NAME_TO.getKey(),  adapter_to==null?"":adapter_to.getAdapterName());
				}
			}
		}
	    rootMap.put(PLACEHOLDER.CURRENT_VALUE_1.getKey(), valueOnTime.getCurrentValue1());
	    rootMap.put(PLACEHOLDER.CURRENT_VALUE_2.getKey(), valueOnTime.getCurrentValue2());
	    rootMap.put(PLACEHOLDER.CONF_VALUE_1.getKey(), confValue1);
	    rootMap.put(PLACEHOLDER.CONF_VALUE_2.getKey(), confValue2);
	    StringWriter out = new StringWriter();
	    try {
			FreemarkerUtil.flushStringTemplateData(alertTemplate, out, rootMap);
		} catch (Exception e) {
			logger.error("解析指标告警模板出错",e);
			throw new NiceException("解析指标告警模板出错",e);
		} 
	    result = out.toString();
		return result;
	}
}
